#ifndef __EPOLL_DEMO_NGNBVNBV_H__
#define __EPOLL_DEMO_NGNBVNBV_H__



#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* for O_DIRECT */
#endif

#ifndef __USE_FILE_OFFSET64
#define __USE_FILE_OFFSET64
#endif

#ifndef __USE_LARGEFILE64
#define __USE_LARGEFILE64
#endif

#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
#endif

// must define __USE_GNU before <pthread.h>.
#define __USE_GNU

#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <malloc.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <signal.h>  
#include <dirent.h>
#include <syslog.h>
#include <sched.h>
#include <time.h>

#include <sys/types.h>
#include <sys/time.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/signalfd.h>  
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/vfs.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <sys/socket.h>


#define EPD_SERVER_EPOLL_FD_MAX		(65536 << 4)
#define EPD_SERVER_LISTEN_QUEUE		8192
#define EPD_SERVER_EPOLL_EVT_MAX	8192


#define EPD_CLIENT_EPOLL_FD_MAX		2
#define EPD_CLIENT_EPOLL_EVT_MAX	1



#define EPD_LOCAL					static

#ifdef _MSC_VER_							// for MSVC
#define EPD_FORCE_INLINE			__forceinline
#elif defined __GNUC__						// for gcc on Linux/Apple OS X
#define EPD_FORCE_INLINE			__inline__ __attribute__((always_inline))
#else
#define EPD_FORCE_INLINE			inline
#endif

#define EPD_LOCAL_INLINE			EPD_LOCAL EPD_FORCE_INLINE

#if defined(__KERNEL__) && defined(__linux__)
#define EPD_LIKELY(expr)			likely((expr))
#define EPD_UNLIKELY(expr)			unlikely((expr))
#else
#define EPD_LIKELY(expr)			(expr)
#define EPD_UNLIKELY(expr)			(expr)
#endif


#define EPD_PACKED					__attribute__((__packed__))

#define EPD_NUM_OF(a)				((int)(sizeof(a)/sizeof((a)[0])))


#define EPD_OFFSET_OF(type, member)	((unsigned long)(&(((type*)0)->member)))
  
  
#define EPD_CONTAINER_OF(ptr, type, member)	((type*)((char*)(ptr) - EPD_OFFSET_OF(type, member)))
  

#define EPD_ALIGN_DOWN(a, size)		((a) & (~((size) - 1)) )
#define EPD_ALIGN_UP(a, size)		(((a) + (size) - 1) & (~((size) - 1)))

#define EPD_TRUE					(0 == 0)
#define EPD_FALSE					(0 == 1)


#define EPD_UINT64_MAX				(~((uint64_t)0))

#define EPD_SIZE_1K					1024UL
#define EPD_SIZE_1M					(EPD_SIZE_1K * EPD_SIZE_1K)
#define EPD_SIZE_1G					(EPD_SIZE_1M * EPD_SIZE_1K)
#define EPD_SIZE_1T					(EPD_SIZE_1G * EPD_SIZE_1K)


#define EPD_NET_IP_QUAD(addr)		((unsigned char *)&addr)[0], ((unsigned char *)&addr)[1], \
  	((unsigned char *)&addr)[2], ((unsigned char *)&addr)[3]


#define EPD_STR_TO_UINT64(a, b, c, d, e, f, g, h)	((((uint64_t)(a)) << 0) | (((uint64_t)(b)) << 8) | (((uint64_t)(c)) << 16) \
		| (((uint64_t)(d)) << 24) | (((uint64_t)(e)) << 32) | (((uint64_t)(f)) << 40) | (((uint64_t)(g)) << 48) | (((uint64_t)(h)) << 56))




typedef enum
{
	EPD_INVALID_PARAM 			= EINVAL, 
	EPD_NO_MEMORY				= ENOMEM, 
	EPD_NO_DEVICE				= ENODEV, 
	EPD_DEVICE_BUSY				= EBUSY, 
	EPD_TRY_AGAIN				= EAGAIN, 
	EPD_INTERRUPTED				= EINTR, 
	EPD_NOT_TYPEWRITER			= ENOTTY, 
	EPD_BAD_ADDRESS				= EFAULT, 
	EPD_NOT_PERMITTED			= EPERM, 
	EPD_NO_SUCH_FILE			= ENOENT, 
	EPD_IO_ERROR				= EIO, 
	
	EPD_OK						= 0, 
	EPD_FAILED					= ~((int)0), 
	
} epd_errno_t;



#define EPD_LOG_ERR		0
#define EPD_LOG_WAR		1
#define EPD_LOG_INF		2
#define EPD_LOG_DBG		3

#define EPD_OUT(fmt, ...)			printf(fmt, ##__VA_ARGS__)

#define EPD_LOG(level, fmt, ...)	printf(fmt, ##__VA_ARGS__)


#define EPD_FUNC_STR				"%-10s"


#define EPD_ERR(fmt, ...) do { EPD_LOG(EPD_LOG_ERR, "[%-12s %03d] " EPD_FUNC_STR " : " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__); } while(0)


#define EPD_WAR(fmt, ...) do { EPD_LOG(EPD_LOG_WAR, EPD_FUNC_STR " : " fmt, __func__, ##__VA_ARGS__); } while(0)


#define EPD_INF(fmt, ...) do { EPD_LOG(EPD_LOG_INF, EPD_FUNC_STR " : " fmt, __func__, ##__VA_ARGS__); } while(0)


#ifdef EPD_DEBUG
#define EPD_DBG(fmt, ...) do { EPD_LOG(EPD_LOG_DBG, EPD_FUNC_STR " : " fmt, __func__, ##__VA_ARGS__); } while(0)
#else /* EPD_DEBUG */
#define EPD_DBG(fmt, ...)	do{} while(0)
#endif /* EPD_DEBUG */


#define EPD_BUG(fmt, ...) \
	do \
	{ \
		EPD_LOG(EPD_LOG_ERR, "%-20s : BUG ! ! ! %s line %d, %s.\n", __func__, __FILE__, __LINE__, __DATE__); \
		EPD_LOG(EPD_LOG_ERR, "%-20s : " fmt "\n", __func__, ##__VA_ARGS__); \
	} while(0)



int epd_epoll_noblock_set(int fd);
int epd_epoll_fd_add(int epollfd, int fd, int oneshot);
int epd_epoll_oneshot_reset(int epollfd, int fd);

int epd_hostname_get(char* hostname, int len);
int epd_system(const char* cmd_str);
int epd_popen_cmd(const char* const cmd_str, char* const out_str, int len);
int epd_popen_str(char* const out_str, int len, const char* fmt, ...);
int epd_popen_std(const char* fmt, ...);



typedef struct epd_req
{
	uint64_t type;
	uint64_t len;
	uint64_t idx;
	uint64_t val;
	uint64_t ret;
	
	uint8_t name[32];
	uint8_t info[64];
} EPD_PACKED epd_req_t;


typedef struct epd_server
{
	int listen_fd;
	
	int epfd;
	
} epd_server_t;

int epd_server_start(epd_server_t* const server, int port);
int epd_server_stop(epd_server_t* const server);
int epd_server_loop(epd_server_t* const server, int (*proc)(int sockfd, int epollfd, void* data), void* data, int* is_break);


typedef struct epd_client
{
	int sock_fd;
	int epfd;
	
	char ip[32];
	int port;
	
} epd_client_t;

int epd_client_conn(epd_client_t* const client, const char* server_ip, int port, int timeout);
int epd_client_disc(epd_client_t* const client, int timeout);
int epd_client_req(epd_client_t* const client, epd_req_t* const req, int timeout);



#endif /* __EPOLL_DEMO_NGNBVNBV_H__ */

